package com.yl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yl.common.SnowflakeIdWorker;
import com.yl.constant.Const;
import com.yl.constant.RedisKeyConstant;
import com.yl.exception.CustomException;
import com.yl.mapper.UserMapper;
import com.yl.mapper.UserRoleMapper;
import com.yl.model.dto.PassDTO;
import com.yl.model.dto.UserDTO;
import com.yl.model.entity.MenuEntity;
import com.yl.model.entity.RoleEntity;
import com.yl.model.entity.UserEntity;
import com.yl.model.entity.UserRoleEntity;
import com.yl.model.vo.MenuTreeVO;
import com.yl.model.vo.RoleVO;
import com.yl.model.vo.UserVO;
import com.yl.security.MyPasswordEncoder;
import com.yl.service.MenuService;
import com.yl.service.RoleService;
import com.yl.service.UserRoleService;
import com.yl.service.UserService;
import com.yl.utils.RedisTools;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    @Resource
    private SnowflakeIdWorker idWorker;

    @Resource
    private MyPasswordEncoder passwordEncoder;


    @Resource
    private UserRoleService sysUserRoleService;

    @Resource
    private RoleService sysRoleService;

    @Resource
    private UserMapper sysUserMapper;

    @Resource
    private MenuService sysMenuService;

    @Resource
    private RedisTools redisTools;


    @Resource
    private UserRoleMapper userRoleMapper;


    @Override
    public UserEntity getByUsername(String username) {
        return getOne(new QueryWrapper<UserEntity>().eq("username", username));
    }

    @Override
    public String getUserAuthorityInfo(Long userId) {

        UserEntity sysUser = sysUserMapper.selectById(userId);
        if(sysUser.getIsDel()) throw new CustomException("未查询到当前用户,请联系管理员");
        //  ROLE_admin,ROLE_normal,sys:user:list,....
        String authority = "";

        if (redisTools.hasKey(RedisKeyConstant.GrantedAuthority + sysUser.getUsername())) {
            authority = (String) redisTools.get("GrantedAuthority:" + sysUser.getUsername());

        } else {
            // 获取角色编码
            List<RoleEntity> roles = sysRoleService.list(new QueryWrapper<RoleEntity>()
                    .inSql("id", "select role_id from t_user_role where user_id = " + userId +" and is_del=false"));

            if (roles.size() > 0) {
                String roleCodes = roles.stream().map(r -> "ROLE_" + r.getCode()).collect(Collectors.joining(","));
                authority = roleCodes.concat(",");
            }

            // 获取菜单操作编码
            List<Long> menuIds = sysUserMapper.getNavMenuIds(userId);
            if (menuIds.size() > 0) {

                List<MenuEntity> menus = sysMenuService.listByIds(menuIds);
                String menuPerms = menus.stream().map(m -> m.getPerms()).collect(Collectors.joining(","));

                authority = authority.concat(menuPerms);
            }
            redisTools.set(RedisKeyConstant.GrantedAuthority + sysUser.getUsername(), authority, 60 * 60);
        }

        return authority;
    }

    @Override
    public void clearUserAuthorityInfo(String username) {
        redisTools.del(RedisKeyConstant.GrantedAuthority+ username);
    }

    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) {

        List<UserEntity> sysUsers = this.list(new QueryWrapper<UserEntity>()
                .inSql("id", "select user_id from t_user_role where role_id = " + roleId));

        sysUsers.forEach(u -> {
            this.clearUserAuthorityInfo(u.getUsername());
        });

    }

    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) {
        List<UserEntity> sysUsers = sysUserMapper.listByMenuId(menuId);

        sysUsers.forEach(u -> {
            this.clearUserAuthorityInfo(u.getUsername());
        });
    }


    @Override
    public UserVO info(Long id) {
        UserEntity sysUser = this.getById(id);
        Assert.notNull(sysUser, "找不到该管理员");
        UserVO userVo = BeanUtil.copyProperties(sysUser, UserVO.class);

        List<RoleVO> roles = sysRoleService.listRolesByUserId(id).stream()
                .map(e -> BeanUtil.copyProperties(e, RoleVO.class))
                .collect(Collectors.toList());

        userVo.setSysRoles(roles);
        return userVo;
    }


    @Override
    public Page<UserVO> pageList(UserDTO userDto) {
        Page<UserEntity> pageData = this.page(new Page<>(userDto.getCurrent(), userDto.getSize()),
                new QueryWrapper<UserEntity>()
                        .eq("is_del",false)
                        .like(StrUtil.isNotBlank(userDto.getUsername()), "username", userDto.getUsername()));

        //返回数据处理数据组装
        Page<UserVO> userVoPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
        List<UserVO> list = pageData.getRecords().stream()
                .map(e -> BeanUtil.copyProperties(e, UserVO.class))
                .collect(Collectors.toList());
        userVoPage.setRecords(list);
        return userVoPage;
    }


    @Override
    public UserVO saveObj(UserEntity entity) {

        entity.setId(idWorker.nextId());
        entity.setCreateTime(new Date());
        entity.setStatus(Const.STATUS_ON);
        entity.setIsDel(false);
        //密码加密
        entity.setPassword(passwordEncoder.encode(entity.getPassword()));
        // 默认头像
        entity.setAvatar(Const.DEFULT_AVATAR);
        boolean b = this.save(entity);
        if (!b) throw new CustomException("新增数据失败");

        return BeanUtil.copyProperties(entity, UserVO.class);

    }

    @Override
    public UserVO updateObj(UserDTO dto) {

        UserEntity user = BeanUtil.copyProperties(dto, UserEntity.class);
        user.setUpdateTime(new Date());
        boolean b = this.updateById(user);

        if (!b) throw new CustomException("更新失败");
        return BeanUtil.copyProperties(user, UserVO.class);
    }

    @Override
    public Boolean del(Long[] ids) {
        int del = sysUserMapper.del(ids);
        if(del==0) throw new CustomException("删除数据失败");
        boolean remove = sysUserRoleService.remove(new QueryWrapper<UserRoleEntity>().in("user_id", ids));
        if (!remove) throw new CustomException("删除失败");
        return true;
    }

    @Override
    public Boolean rolePerm(Long userId, Long[] roleIds) {

        List<UserRoleEntity> userRoles = Arrays.stream(roleIds)
                .map(r -> {
                    UserRoleEntity sysUserRole = new UserRoleEntity();
                    sysUserRole.setRoleId(r);
                    sysUserRole.setUserId(userId);
                    sysUserRole.setIs_del(false);
                    return sysUserRole;
                })
                .collect(Collectors.toList());


        int i = userRoleMapper.removeRole(userId);
        if (i==0) throw new CustomException("删除用户角色表失败");


        sysUserRoleService.saveBatch(userRoles);
        // 删除缓存
        UserEntity sysUser = this.getById(userId);
        this.clearUserAuthorityInfo(sysUser.getUsername());
        return true;
    }

    @Override
    public Boolean repass(String userId) {
        UserEntity sysUser = this.getById(userId);

        sysUser.setPassword(passwordEncoder.encode(Const.DEFAULT_PASSWORD));
        sysUser.setUpdateTime(new Date());

        this.updateById(sysUser);

        return true;
    }

    @Override
    public Boolean updatePass(PassDTO passDto) {
        UserEntity sysUser = this.getByUsername(passDto.getUsername());

        boolean matches = passwordEncoder.matches(passDto.getCurrentPass(), sysUser.getPassword());
        if (!matches) {
            throw new CustomException("旧密码不正确");
        }
        sysUser.setPassword(passwordEncoder.encode(passDto.getPassword()));
        sysUser.setUpdateTime(new Date());

        boolean b = this.updateById(sysUser);
        if (!b) throw new CustomException("修改密码失败");
        return true;
    }


    @Override
    public Map<Object, Object> nav(String username) {
        UserEntity sysUser = this.getByUsername(username);

        // 获取权限信息
        String authorityInfo = this.getUserAuthorityInfo(sysUser.getId());// ROLE_admin,ROLE_normal,sys:user:list,....
        String[] authorityInfoArray = StringUtils.tokenizeToStringArray(authorityInfo, ",");

        // 获取导航栏信息
        List<MenuTreeVO> navs = sysMenuService.getCurrentUserNav();

        return MapUtil.builder()
                .put("authoritys", authorityInfoArray)
                .put("nav", navs)
                .map();
    }


    /**
     * 获取登陆用户信息
     * */
    public UserEntity getLoginUserName(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        if (StringUtils.isEmpty(username)) throw new CustomException("未获取到登陆用户信息,请联系管理员");
        UserEntity byUsername = this.getByUsername(username);
        return byUsername;
    }
}
